﻿#region Using

using System;

using Common.Base;
using Common.Extensions;

using GameCommon.Args;
using GameCommon.Manager;
using GameCommon.ManagerInterfaces;
using GameCommon.Services;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

using StructureMap.Source;

#endregion

namespace GameCommon.HitBoxes
{
    public class HexagonHitBox : HitBox
    {
        private readonly Texture2D texture2D;

        public HexagonHitBox(string id, Dimension dimension, string command)
            : base(id)
        {
            this.Layer = 99;
            this.Command = command;
            this.Dimension = dimension;
            this.texture2D = Managers.ContentManager.GetRectangle(Color.Red);
        }

        //// TODO Remove HitBox drawing
        public override void Draw(IDrawingManager manager, GameTime gameTime)
        {
            //// this.DrawingService.Draw(manager, this.texture2D, this.Dimension, 0.5f, this.Layer);
        }

        public override bool IsPointInHitbox(Position point)
        {
            if (!this.Rectangle.IsPointInRectangle(point))
            {
                return false;
            }

            if (this.IsPointInTopLeftTriangle(point))
            {
                return false;
            }

            if (this.IsPointInTopRightTriangle(point))
            {
                return false;
            }

            if (this.IsPointInBottomLeftTriangle(point))
            {
                return false;
            }

            if (this.IsPointInBottomRightTriangle(point))
            {
                return false;
            }

            return true;
        }

        private static bool IsPointInTriangle(Position point1, Position point2, Position point3, Position point)
        {
            //// Compute vectors        
            var v0 = point2 - point1;
            var v1 = point3 - point1;
            var v2 = point - point1;

            double dot00;
            double dot01;
            double dot02;
            double dot11;
            double dot12;
            ComputeDotProducts(v0, v1, v2, out dot00, out dot01, out dot02, out dot11, out dot12);

            // Compute barycentric coordinates
            var invDenom = 1 / ((dot00 * dot11) - (dot01 * dot01));
            var u = ((dot11 * dot02) - (dot01 * dot12)) * invDenom;
            var v = ((dot00 * dot12) - (dot01 * dot02)) * invDenom;

            //// Check if point is in triangle
            return (u >= 0) && (v >= 0) && (u + v < 1);
        }

        private static void ComputeDotProducts(Position v0, Position v1, Position v2, out double dot00, out double dot01, out double dot02, out double dot11, out double dot12)
        {
            // Compute dot products
            dot00 = v0.Dot(v0);
            dot01 = v0.Dot(v1);
            dot02 = v0.Dot(v2);
            dot11 = v1.Dot(v1);
            dot12 = v1.Dot(v2);

            var length = 0;
            if (dot00.ToString().Length > length)
            {
                length = dot00.ToString().Length;
            }

            if (dot01.ToString().Length > length)
            {
                length = dot01.ToString().Length;
            }

            if (dot02.ToString().Length > length)
            {
                length = dot02.ToString().Length;
            }

            if (dot11.ToString().Length > length)
            {
                length = dot11.ToString().Length;
            }

            if (dot12.ToString().Length > length)
            {
                length = dot12.ToString().Length;
            }

            var faktor = 1;
            for (var i = 0; i < length; i++)
            {
                faktor *= 10;
            }

            dot00 /= faktor;
            dot01 /= faktor;
            dot02 /= faktor;
            dot11 /= faktor;
            dot12 /= faktor;
        }

        private bool IsPointInBottomRightTriangle(Position point)
        {
            var point1 = new Position(this.Dimension.X + this.Dimension.Width, this.Dimension.Y + this.Dimension.Height);
            var point2 = new Position(point1.X, point1.Y - (this.Dimension.Height / 2));
            var point3 = new Position((int)Math.Round(point1.X - ((this.Dimension.Height / 2) * Math.Tan(0.5235))), point1.Y); // 30°

            return IsPointInTriangle(point1, point2, point3, point);
        }

        private bool IsPointInBottomLeftTriangle(Position point)
        {
            var point1 = new Position(this.Dimension.Position.X, this.Dimension.Y + this.Dimension.Height);
            var point2 = new Position(point1.X, point1.Y - (this.Dimension.Height / 2));
            var point3 = new Position((int)Math.Round(point1.X + ((this.Dimension.Height / 2) * Math.Tan(0.5235))), point1.Y); // 30°

            return IsPointInTriangle(point1, point2, point3, point);
        }

        private bool IsPointInTopRightTriangle(Position point)
        {
            var point1 = new Position(this.Dimension.X + this.Dimension.Width, this.Dimension.Position.Y);
            var point2 = new Position(point1.X, point1.Y + (this.Dimension.Height / 2));
            var point3 = new Position((int)Math.Round(point1.X - ((this.Dimension.Height / 2) * Math.Tan(0.5235))), point1.Y); // 30°

            return IsPointInTriangle(point1, point2, point3, point);
        }

        private bool IsPointInTopLeftTriangle(Position point)
        {
            var point1 = new Position(this.Dimension.Position);
            var point2 = new Position(point1.X, point1.Y + (this.Dimension.Height / 2));
            var point3 = new Position((int)Math.Round(point1.X + ((this.Dimension.Height / 2) * Math.Tan(0.5235))), point1.Y); // 30°

            return IsPointInTriangle(point1, point2, point3, point);
        }
    }
}